'''
Created on Jan 25, 2010

@author: madsk
'''

from PyQt4 import QtCore
from imageprocessing import ImageWorker
from StringIO import StringIO
from PIL import Image

class ManipulatedImage(QtCore.QObject):
    """
    Represents an image being manipulated in the editor.
    This class maintains an operation history that may be used for
    undo purposes and that may be used to get a list of operations
    performed when the operations are to be applied to the original
    image.
    """
    
    finished = QtCore.pyqtSignal(bool)
    
    def __init__(self, image):
        """
        Constuctor.
        @type image: MultiImage
        @param image: The MultiImage instance given to the editor
                      by the browser.
        """
        super(ManipulatedImage, self).__init__()
        self._image = image
        self._history = []
        self._worker = ImageWorker()
        self._worker.finished.connect(self._handleWorkerFinished)
    
    def isModified(self):
        """
        Returns whether or not the image has been changed since the creation
        of the ManipulatedImage instance.
        """
        return len(self._history) > 0
    
    def performOperation(self, operation, args):
        """
        Perform an image manipulation operation.
        @type operation: str
        @param operation: The operation that has been performed.
        @type args: any
        @param args: The arguments given to the image manipulation 
                     operation.
        """
        # Update the history.
        self._history.append((operation, args, self._image.preview))
        
        # Check whether this is a scale operation. If so we need not preview it.
        if operation == 'scale':
            self.finished.emit(True)
        else:
            # Launch the ImageWorker thread.
            sio = StringIO()
            self._image.preview.save(sio, 'JPEG', quality=95)
            self._worker.image = sio.getvalue()
            self._worker.operation = operation
            self._worker.args = args
            self._worker.start()
        
    def undoOperation(self):
        """
        Removes the last operation.
        """
        if len(self._history) != 0:
            self._image.preview = self._history.pop()[2]
        else:
            raise Exception('No operations to undo.')
        
    def reset(self):
        """
        Returns the image to its original state.
        """
        if len(self._history) != 0:
            self._image.preview = self._history[0][2]
            self._history = []

    def wait(self):
        """Wait for the worker thread to finish."""
        return self._worker.wait()
    
    def operations(self):
        """
        Returns a list of the operations performed to the image.
        """
        operations = []
        for operation, args, _ in self._history:
            operations.append((operation, args))
        return operations
    
    # ----- PRIVATE FUNCTIONS ----- #
    
    def _handleWorkerFinished(self):
        if self._worker.success:
            sio = StringIO(self._worker.image)
            self._image.preview = Image.open(sio)
            self.finished.emit(True)
        else:
            self.finished.emit(False)


    # ----- PROPERTIES ----- #
            
    def pixmap(): #@NoSelf
        def fget(self):
            return self._image.pixmap
        return locals()
    pixmap = property(**pixmap())
    
    def path(): #@NoSelf
        def fget(self):
            return self._image.path
        return locals()
    path = property(**path())